Welcome to my notebook covering the use of the tidycensus R package
for extracting and evaluating census data in the state of Oregon. In
part A We are interested in uncovering the percentages of the population
with graduate level degrees at a county level. Part B will continue to
focus on education data, Stay tuned to find out more!
Import Libraries
Start by importing the list of libraries that will assist us in
connecting with the Census Bureau’s APIs and visualizing the desired
data.
library(tidycensus) # connect with the census bureau API
library(tidyverse) # data wrangling
library(mapview) # spatial data visualizer
library(plotly) # graph / chart visualizer
library(ggiraph) # graph / chart visualizer
library(ggplot2) # graph / chart visualizer
library(DT) # fancy tables
library(scales) # scales map data to aesthetics
library(sf) # spatial data package
library(tigris) # erase water
library(cowplot) # plot_grid()
Part A
Data Source
We will use the get_acs() function from the tidycensus package to
pull data from the census bureau. The function defaults to the 2017-2021
5-year ACS dataset. Which is necessary for us, since there are a list of
counties in Oregon with a population of less than 65,000.
The data we would like to visualize is the percent of the population
that have a graduate degree at the county level in the state of
Oregon.
# use the get_acs() function for importing data
or_grads <- get_acs(
geography = "county", # county level geography
variables = "DP02_0066P", # variable for percent of the population that have a graduate degrees
state = "OR",
year = 2021,
progress_bar = FALSE
)
Data Manipulation & DataTables
Data Visualization & Analysis
All tables in the tidycensus package come with a margin of error
column to give us an understanding of accuracy in the dataset.
Typically, census data from geographies of larger population have a
lower margin of error.
Lets plot the MOE variable with our estimate variable below.
# create plot revealing moe and estimate variables
or_plot_errorbar <- ggplot(or_grads, aes(x = estimate, y = reorder(NAME, estimate))) + # sort by counties high to low
geom_errorbar(aes(xmin = estimate - moe, xmax = estimate + moe),
width = 0.5, linewidth = 0.5) +
geom_point(color = "gold", size = 3) + # state color gold for point data
scale_x_continuous(labels = function(x) paste0(x, '%')) + # concatenate '%' to estimate data
scale_y_discrete(labels = function(x) str_remove(x, " County, Oregon|, Oregon")) + # strip 'county' from the name column
labs(title = "% Population with graduate degrees, 2017-2021 ACS", # use appropriate title
subtitle = "Counties in Oregon", # use appropriate subtitle
caption = "Data acquired with R and tidycensus. Error bars represent margin of error around estimates.",
"ACS estimate",
y = "",
x = "Percentage") +
theme_minimal(base_size = 12) # remove tick marks
or_plot_errorbar # print plot

Figure 3 above reveals the margin of error
associated with the estimate data.
Interative Plots
Using ggplotly() I’m going to recreate the plot above but leveraging
the interactivity of the plotly library.
# use ggplotly() and add a tooltip, and extend the margins of the plot
ggplotly(or_plot_errorbar, tooltip = "x")%>%
layout(margin = list(l = 50, r = 50, b = 50, t = 50))
Figure 4 Hover over the points in the plot above to
see the interactive tootip.
Part B
Continuing with the theme of education, lets import more data
through the tidycensus package.
What percentage of people with bachelor’s degrees rent or
own their home in Washington and Multnomah County, Oregon at the tract
level?
These two counties together cover the most populus city of Oregon.
You guessed it, Portland.
To find variables that will assist us in our analysis, we will use
the load_variables() function to filter through the ACS data.
# use the load_variables function() with the year and ACS 5 year parameter
vars <- load_variables(2021, "acs5")
# load vars into a datatable
datatable(vars)
Figure 5 By using the search feature in the
datatable, you see examples of available results. For example search
“bachelor’s” to find variable codes moving forward.
Import Data
We will need to pull in two datasets and eventually merge the
results into one table.
“B25013_006” is the population of people with bachelor’s degrees
that own their home.
“B25013_011” is the population of people with bachelor’s degrees
that rent their home.
# import data at the tract level for home owners
bach_owners <- erase_water(get_acs(
geography = "tract",
variables = "B25013_006",
state = "OR",
county = c("Washington", "Multnomah"), # select multiple counties
geometry = TRUE, # get multipolygon data of Oregon tracts
progress_bar = FALSE
))
# import data at the tract level for renters
bach_renters <- get_acs(
geography = "tract",
variables = "B25013_011",
state = "OR",
county = c("Washington", "Multnomah"), # select multiple counties
geometry = FALSE, # geometry is false because we are getting our multipolygon data in the owners dataset.
progress_bar = FALSE
)
Data Wrangling
Use functions of the tidyverse to rename, select, and mutuate
columns to fit our analysis. Since the estimate data originally comes as
a count, we will sum up renters and owners to a create a total column
and a percentage column for each.
# clarify the name of the estimate & moe columns before joining
bach_owners <- bach_owners %>%
rename(estimate_owners = estimate, moe_owners = moe)
# clarify the name of the estimate & moe columns before joining
bach_renters <- bach_renters %>%
rename(estimate_renters = estimate, moe_renters = moe) %>%
select(GEOID, estimate_renters, moe_renters) # drop unnecessary values
# join dataframes on GEOID, and create percent columns of each category
bach_housing <- left_join(bach_owners, bach_renters, by='GEOID') %>%
select(GEOID, NAME, estimate_owners, estimate_renters, moe_owners, moe_renters, geometry) %>%
mutate(estimate_total = estimate_renters + estimate_owners) %>% # create a total value
mutate(percent_renters = (estimate_renters/estimate_total)*100) %>% # create a % of renters
mutate(percent_owners = (estimate_owners/estimate_total)*100) %>% # create a % of owners
mutate(across(where(is.numeric), ~ round(.x, digits = 2)))
Error in exists(cacheKey, where = .rs.WorkingDataEnv, inherits = FALSE) :
invalid first argument
Error in assign(cacheKey, frame, .rs.CachedDataEnv) :
attempt to use zero-length variable name
Data Visualization & Analysis
Now that the data is wrangled we can view it in a table before
mapping and plotting the desired variables.
bach_housing_table <- bach_housing %>%
select(NAME, percent_renters, percent_owners) %>%
arrange(-percent_renters)
datatable(bach_housing_table)
Figure 6 As suspected in Portland there are a high
number of renters with bachelor’s degrees. Multiple tracts reveal areas
with 100% of our particular study rent their homes.
We are going to start with the mapview package to get a glimplse
into the data.
# use the percent_renters variable to display in the mapview
mapview(bach_housing,
layer.name = "% Renters<br/>2017-2021 ACS", # change layer name
zcol = "percent_renters") # select a variable to display
Figure 7 Mapview is programmtically a simple way to
display insightful and interactive data. We can now easiy visualize that
the city center has the highest number of renters versus owners and
shifts as you move into the more rural areas.
Now that we have sampled the data in mapview, lets use ggplot to
create a set of chloropleth maps for both categories (renting and
owning).
# create ggplot for renters
renters <- ggplot(bach_housing, aes(fill = percent_renters)) + # fill with percent renters
geom_sf() +
theme_void() +
scale_fill_viridis_c(option = "rocket") + # use rocket color scheme
labs(title = "Percent of Population w/ Bachelor's Degree Renting by Census tract", # create clear titles and captions
subtitle = "Washington & Multnomah County, Oregon",
fill = "% Renting",
caption = "2017-2021 ACS | tidycensus R package")
# create ggplot for owners
owners <- ggplot(bach_housing, aes(fill = percent_owners)) +
geom_sf() +
theme_void() +
scale_fill_viridis_c(option = "rocket") + # use rocket color scheme
labs(title = "Percent of Population w/ Bachelor's Degree That Own Their Home by Census tract", # create clear titles and captions
subtitle = "Washington & Multnomah County, Oregon",
fill = "% Owners",
caption = "2017-2021 ACS | tidycensus R package")
# use plot_grid from the cowplot library to stack the maps
plot_grid(renters, owners, ncol=1, align = "hv")

Figure 8
LS0tDQp0aXRsZTogIkhpZ2hlciBlZHVjYXRpb24gJSBpbiBPcmVnb24gLSBBbGlzIHZvbGF0IHByb3ByaWlzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCiMjIyMgV2VsY29tZSB0byBteSBub3RlYm9vayBjb3ZlcmluZyB0aGUgdXNlIG9mIHRoZSB0aWR5Y2Vuc3VzIFIgcGFja2FnZSBmb3IgZXh0cmFjdGluZyBhbmQgZXZhbHVhdGluZyBjZW5zdXMgZGF0YSBpbiB0aGUgc3RhdGUgb2YgT3JlZ29uLiBJbiBwYXJ0IEEgV2UgYXJlIGludGVyZXN0ZWQgaW4gdW5jb3ZlcmluZyB0aGUgcGVyY2VudGFnZXMgb2YgdGhlIHBvcHVsYXRpb24gd2l0aCBncmFkdWF0ZSBsZXZlbCBkZWdyZWVzIGF0IGEgY291bnR5IGxldmVsLiBQYXJ0IEIgd2lsbCBjb250aW51ZSB0byBmb2N1cyBvbiBlZHVjYXRpb24gZGF0YSwgU3RheSB0dW5lZCB0byBmaW5kIG91dCBtb3JlIQ0KDQojIyMgSW1wb3J0IExpYnJhcmllcw0KDQojIyMjIyBTdGFydCBieSBpbXBvcnRpbmcgdGhlIGxpc3Qgb2YgbGlicmFyaWVzIHRoYXQgd2lsbCBhc3Npc3QgdXMgaW4gY29ubmVjdGluZyB3aXRoIHRoZSBDZW5zdXMgQnVyZWF1J3MgQVBJcyBhbmQgdmlzdWFsaXppbmcgdGhlIGRlc2lyZWQgZGF0YS4gDQpgYGB7Y3NzLCBlY2hvPUZBTFNFfQ0KcCB7DQogIG1hcmdpbi1ib3R0b206IDBweDsNCn0NCmBgYA0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQpsaWJyYXJ5KHRpZHljZW5zdXMpICMgY29ubmVjdCB3aXRoIHRoZSBjZW5zdXMgYnVyZWF1IEFQSQ0KbGlicmFyeSh0aWR5dmVyc2UpICMgZGF0YSB3cmFuZ2xpbmcNCmxpYnJhcnkobWFwdmlldykgIyBzcGF0aWFsIGRhdGEgdmlzdWFsaXplcg0KbGlicmFyeShwbG90bHkpICMgZ3JhcGggLyBjaGFydCB2aXN1YWxpemVyDQpsaWJyYXJ5KGdnaXJhcGgpICMgZ3JhcGggLyBjaGFydCB2aXN1YWxpemVyDQpsaWJyYXJ5KGdncGxvdDIpICMgZ3JhcGggLyBjaGFydCB2aXN1YWxpemVyDQpsaWJyYXJ5KERUKSAjIGZhbmN5IHRhYmxlcw0KbGlicmFyeShzY2FsZXMpICMgc2NhbGVzIG1hcCBkYXRhIHRvIGFlc3RoZXRpY3MNCmxpYnJhcnkoc2YpICMgc3BhdGlhbCBkYXRhIHBhY2thZ2UNCmxpYnJhcnkodGlncmlzKSAjIGVyYXNlIHdhdGVyDQpsaWJyYXJ5KGNvd3Bsb3QpICMgcGxvdF9ncmlkKCkNCmBgYA0KIyMjIFBhcnQgQQ0KPGhyIC8+DQojIyMgRGF0YSBTb3VyY2UNCg0KIyMjIyMgV2Ugd2lsbCB1c2UgdGhlIGdldF9hY3MoKSBmdW5jdGlvbiBmcm9tIHRoZSB0aWR5Y2Vuc3VzIHBhY2thZ2UgdG8gcHVsbCBkYXRhIGZyb20gdGhlIGNlbnN1cyBidXJlYXUuIFRoZSBmdW5jdGlvbiBkZWZhdWx0cyB0byB0aGUgMjAxNy0yMDIxIDUteWVhciBBQ1MgZGF0YXNldC4gV2hpY2ggaXMgbmVjZXNzYXJ5IGZvciB1cywgc2luY2UgdGhlcmUgYXJlIGEgbGlzdCBvZiBjb3VudGllcyBpbiBPcmVnb24gd2l0aCBhIHBvcHVsYXRpb24gb2YgbGVzcyB0aGFuIDY1LDAwMC4gDQoNCiMjIyMjIFRoZSBkYXRhIHdlIHdvdWxkIGxpa2UgdG8gdmlzdWFsaXplIGlzIHRoZSBwZXJjZW50IG9mIHRoZSBwb3B1bGF0aW9uIHRoYXQgaGF2ZSBhIGdyYWR1YXRlIGRlZ3JlZSBhdCB0aGUgY291bnR5IGxldmVsIGluIHRoZSBzdGF0ZSBvZiBPcmVnb24uICANCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyB1c2UgdGhlIGdldF9hY3MoKSBmdW5jdGlvbiBmb3IgaW1wb3J0aW5nIGRhdGENCm9yX2dyYWRzIDwtIGdldF9hY3MoDQogIGdlb2dyYXBoeSA9ICJjb3VudHkiLCAjIGNvdW50eSBsZXZlbCBnZW9ncmFwaHkNCiAgdmFyaWFibGVzID0gIkRQMDJfMDA2NlAiLCAjIHZhcmlhYmxlIGZvciBwZXJjZW50IG9mIHRoZSBwb3B1bGF0aW9uIHRoYXQgaGF2ZSBhIGdyYWR1YXRlIGRlZ3JlZXMNCiAgc3RhdGUgPSAiT1IiLCANCiAgeWVhciA9IDIwMjEsDQogIHByb2dyZXNzX2JhciA9IEZBTFNFDQopDQpgYGANCiMjIyBEYXRhIE1hbmlwdWxhdGlvbiAmIERhdGFUYWJsZXMNCg0KIyMjIyMgQW4gaW1wb3J0YW50IGFzcGVjdCBvZiB0aGUgdGlkeWNlbnN1cyBwYWNrYWdlIGlzIHRoYXQgaXMgcHJlc2VudHMgdGhlIGRhdGEgdG8gdXMgaW4gYSB0aWR5IGZvcm1hdC4gVGhlIGRhdGEgaXMgcHJlLWNsZWFuZWQgYW5kIHRha2VzIGxpdHRsZSB3cmFuZ2xpbmcgdG8gYW5zd2VyIHF1ZXN0aW9ucy4NCmBgYHtyfQ0KIyBmaWx0ZXIgYW5kIGFycmFuZ2UgcmVzdWx0cw0Kb3JfZ3JhZHNfdGFibGUgPC0gb3JfZ3JhZHMgJT4lDQogIHNlcGFyYXRlKE5BTUUsIGludG8gPSBjKCJjb3VudHkiLCAic3RhdGUiKSwgc2VwID0gIiwgIikgJT4lICMgY3JlYXRlIGNvdW50eSBhbmQgc3RhdGUgY29sdW1ucw0KICBhcnJhbmdlKC1lc3RpbWF0ZSkgJT4lICMgc29ydCBieSBlc3RpbWF0ZSBkZXNjZW5kaW5nDQogIHNlbGVjdChjb3VudHksIHN0YXRlLCBlc3RpbWF0ZSwgbW9lKSAjIHNlbGVjdCBpbXBvcnRhbnQgY29sdW1ucw0KYGBgDQoNCiMjIyMjIEJ5IHVzaW5nIHRoZSBkYXRhdGFibGUoKSBmdW5jdGlvbiBmcm9tIHRoZSBEVCBsaWJyYXJ5IHdlIGNhbiBmaWx0ZXIgb3VyIHJlc3VsdHMgdG8gc2VlIHRoZSBkZXNpcmVkIGluZm9ybWF0aW9uLg0KYGBge3J9DQojIGZ1bmN0aW9uIGZyb20gdGhlIERUIGxpYnJhcnkgdG8gY3JlYXRlIGEgZGF0YXRhYmxlDQpkYXRhdGFibGUob3JfZ3JhZHNfdGFibGUpDQpgYGANCioqRmlndXJlIDEqKiBhYm92ZSByZXZlYWxzIHRoZSBkYXRhIGltcG9ydGVkIGZyb20gdGhlIGdldF9hY3MoKSBmdW5jdGlvbi4gUmVzdWx0cyBjb25jbHVkZSB0aGF0IHRoZSB0b3AgMyBjb3VudGllcyB3aXRoIGdyYWR1YXRlIGRlZ3JlZXMgaXMgQmVudG9uLCBNdWx0bm9tYWgsIGFuZCBXYXNoaW5ndG9uLiBCb3R0b20gMyBjb3VudGllcyBhcmUgTWFsaGV1ciwgR2lsbGlhbSwgYW5kIE1vcnJvdy4NCg0KPGhyIC8+DQoNCiMjIyBEYXRhIFZpc3VhbGl6YXRpb24gJiBBbmFseXNpcw0KDQojIyMjIyBOb3cgdGhhdCBvdXIgZGF0YSBpcyBpbXBvcnRlZCBhbmQgaW4gYSBwcm9wZXIgZm9ybWF0LiBXZSBjYW4gYmVnaW4gdXNpbmcgZ2dwbG90IHRvIHZpc3VhbGl6ZSB0aGUgcGVyY2VudGFnZSBvZiB0aGUgb3JlZ29uIHBvcHVsYXRpb24gdGhhdCBncmFkdWF0ZSBoYXZlIGRlZ3JlZXMuIA0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OS41fQ0KIyB1c2UgZ2dwbG90IHdpdGggZXN0aW1hdGUgYXMgdGhlIHggYXhpcyBhbmQgY291bnR5IGFzIHRoZSB5IGF4aXMNCm9yX3Bsb3QgPC0gZ2dwbG90KG9yX2dyYWRzX3RhYmxlLCBhZXMoeCA9IGVzdGltYXRlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJlb3JkZXIoY291bnR5LCBlc3RpbWF0ZSkpKSArICMgc29ydCBieSBjb3VudGllcyBoaWdoIHRvIGxvdw0KICBnZW9tX3BvaW50KGNvbG9yPSJuYXZ5Iiwgc2l6ZSA9IDMpICsgIyBzdGF0ZSBjb2xvciBuYXZ5IGJsdWUgZm9yIHBvaW50IGRhdGENCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAnJScpKSArICMgY29uY2F0ZW5hdGUgJyUnIHRvIGVzdGltYXRlIGRhdGENCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJfcmVtb3ZlKHgsICIgQ291bnR5IikpICsgIyBzdHJpcCAnY291bnR5JyBmcm9tIHRoZSBuYW1lIGNvbHVtbg0KICBsYWJzKHRpdGxlID0gIiUgUG9wdWxhdGlvbiB3aXRoIGdyYWR1YXRlIGRlZ3JlZXMsIDIwMTctMjAyMSBBQ1MiLCAjIHVzZSBhcHByb3ByaWF0ZSB0aXRsZQ0KICAgICAgIHN1YnRpdGxlID0gIkNvdW50aWVzIGluIE9yZWdvbiIsICMgdXNlIGFwcHJvcHJpYXRlIHN1YnRpdGxlDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIGFjcXVpcmVkIHdpdGggUiBhbmQgdGlkeWNlbnN1cyIsDQogICAgICAgeCA9ICJBQ1MgZXN0aW1hdGUgUGVyY2VudGFnZSIsDQogICAgICAgeSA9ICIiKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICMgcmVtb3ZlIHRpY2sgbWFya3MgDQogIA0Kb3JfcGxvdCAjIHByaW50IHBsb3QNCmBgYA0KKipGaWd1cmUgMioqIGFib3ZlIHBsb3RzIHRoZSBjb3VudGllcyBieSBlc3RpbWF0ZSB2YWx1ZSBpbiBhIGRlc2NlbmRpbmcgb3JkZXIuIFdlIGdldCBhIGZ1bGwgcGljdHVyZSBvZiBvdXIgcmVzdWx0cyB3aXRob3V0IGhhdmluZyB0byBmaWx0ZXIgdGhyb3VnaCBtdWx0aXBsZSBwYWdlcyBpbiBhIHRhYmxlLg0KDQo8aHIgLz4NCg0KIyMjIyMgQWxsIHRhYmxlcyBpbiB0aGUgdGlkeWNlbnN1cyBwYWNrYWdlIGNvbWUgd2l0aCBhIG1hcmdpbiBvZiBlcnJvciBjb2x1bW4gdG8gZ2l2ZSB1cyBhbiB1bmRlcnN0YW5kaW5nIG9mIGFjY3VyYWN5IGluIHRoZSBkYXRhc2V0LiBUeXBpY2FsbHksIGNlbnN1cyBkYXRhIGZyb20gZ2VvZ3JhcGhpZXMgb2YgbGFyZ2VyIHBvcHVsYXRpb24gaGF2ZSBhIGxvd2VyIG1hcmdpbiBvZiBlcnJvci4NCg0KIyMjIyMgTGV0cyBwbG90IHRoZSBNT0UgdmFyaWFibGUgd2l0aCBvdXIgZXN0aW1hdGUgdmFyaWFibGUgYmVsb3cuIA0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OS41fQ0KIyBjcmVhdGUgcGxvdCByZXZlYWxpbmcgbW9lIGFuZCBlc3RpbWF0ZSB2YXJpYWJsZXMNCm9yX3Bsb3RfZXJyb3JiYXIgPC0gZ2dwbG90KG9yX2dyYWRzLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gcmVvcmRlcihOQU1FLCBlc3RpbWF0ZSkpKSArICMgc29ydCBieSBjb3VudGllcyBoaWdoIHRvIGxvdw0KICBnZW9tX2Vycm9yYmFyKGFlcyh4bWluID0gZXN0aW1hdGUgLSBtb2UsIHhtYXggPSBlc3RpbWF0ZSArIG1vZSksIA0KICAgICAgICAgICAgICAgIHdpZHRoID0gMC41LCBsaW5ld2lkdGggPSAwLjUpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJnb2xkIiwgc2l6ZSA9IDMpICsgIyBzdGF0ZSBjb2xvciBnb2xkIGZvciBwb2ludCBkYXRhDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBwYXN0ZTAoeCwgJyUnKSkgKyAjIGNvbmNhdGVuYXRlICclJyB0byBlc3RpbWF0ZSBkYXRhDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gZnVuY3Rpb24oeCkgc3RyX3JlbW92ZSh4LCAiIENvdW50eSwgT3JlZ29ufCwgT3JlZ29uIikpICsgIyBzdHJpcCAnY291bnR5JyBmcm9tIHRoZSBuYW1lIGNvbHVtbg0KICBsYWJzKHRpdGxlID0gIiUgUG9wdWxhdGlvbiB3aXRoIGdyYWR1YXRlIGRlZ3JlZXMsIDIwMTctMjAyMSBBQ1MiLCAjIHVzZSBhcHByb3ByaWF0ZSB0aXRsZQ0KICAgICAgIHN1YnRpdGxlID0gIkNvdW50aWVzIGluIE9yZWdvbiIsICMgdXNlIGFwcHJvcHJpYXRlIHN1YnRpdGxlDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIGFjcXVpcmVkIHdpdGggUiBhbmQgdGlkeWNlbnN1cy4gRXJyb3IgYmFycyByZXByZXNlbnQgbWFyZ2luIG9mIGVycm9yIGFyb3VuZCBlc3RpbWF0ZXMuIiwNCiAgICAgICAiQUNTIGVzdGltYXRlIiwNCiAgICAgIHkgPSAiIiwNCiAgICAgIHggPSAiUGVyY2VudGFnZSIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgIyByZW1vdmUgdGljayBtYXJrcyANCiAgDQpvcl9wbG90X2Vycm9yYmFyICMgcHJpbnQgcGxvdA0KYGBgDQoqKkZpZ3VyZSAzKiogYWJvdmUgcmV2ZWFscyB0aGUgbWFyZ2luIG9mIGVycm9yIGFzc29jaWF0ZWQgd2l0aCB0aGUgZXN0aW1hdGUgZGF0YS4NCg0KPGhyIC8+DQoNCiMjIyBJbnRlcmF0aXZlIFBsb3RzDQoNCiMjIyMjIFVzaW5nIGdncGxvdGx5KCkgSSdtIGdvaW5nIHRvIHJlY3JlYXRlIHRoZSBwbG90IGFib3ZlIGJ1dCBsZXZlcmFnaW5nIHRoZSBpbnRlcmFjdGl2aXR5IG9mIHRoZSBwbG90bHkgbGlicmFyeS4NCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTkuNX0NCiMgdXNlIGdncGxvdGx5KCkgYW5kIGFkZCBhIHRvb2x0aXAsIGFuZCBleHRlbmQgdGhlIG1hcmdpbnMgb2YgdGhlIHBsb3QNCmdncGxvdGx5KG9yX3Bsb3RfZXJyb3JiYXIsIHRvb2x0aXAgPSAieCIpJT4lIA0KICBsYXlvdXQobWFyZ2luID0gbGlzdChsID0gNTAsIHIgPSA1MCwgYiA9IDUwLCB0ID0gNTApKQ0KYGBgDQoqKkZpZ3VyZSA0KiogSG92ZXIgb3ZlciB0aGUgcG9pbnRzIGluIHRoZSBwbG90IGFib3ZlIHRvIHNlZSB0aGUgaW50ZXJhY3RpdmUgdG9vdGlwLg0KDQo8aHIgLz4NCg0KIyMjIFBhcnQgQg0KDQo8aHIgLz4NCg0KIyMjIyMgQ29udGludWluZyB3aXRoIHRoZSB0aGVtZSBvZiBlZHVjYXRpb24sIGxldHMgaW1wb3J0IG1vcmUgZGF0YSB0aHJvdWdoIHRoZSB0aWR5Y2Vuc3VzIHBhY2thZ2UuIA0KDQojIyMjIyA8c3Ryb25nPldoYXQgcGVyY2VudGFnZSBvZiBwZW9wbGUgd2l0aCBiYWNoZWxvcidzIGRlZ3JlZXMgcmVudCBvciBvd24gdGhlaXIgaG9tZSBpbiBXYXNoaW5ndG9uIGFuZCBNdWx0bm9tYWggQ291bnR5LCBPcmVnb24gYXQgdGhlIHRyYWN0IGxldmVsPzwvc3Ryb25nPg0KDQojIyMjIyBUaGVzZSB0d28gY291bnRpZXMgdG9nZXRoZXIgY292ZXIgdGhlIG1vc3QgcG9wdWx1cyBjaXR5IG9mIE9yZWdvbi4gWW91IGd1ZXNzZWQgaXQsIFBvcnRsYW5kLg0KDQojIyMjIyBUbyBmaW5kIHZhcmlhYmxlcyB0aGF0IHdpbGwgYXNzaXN0IHVzIGluIG91ciBhbmFseXNpcywgd2Ugd2lsbCB1c2UgdGhlIGxvYWRfdmFyaWFibGVzKCkgZnVuY3Rpb24gdG8gZmlsdGVyIHRocm91Z2ggdGhlIEFDUyBkYXRhLiANCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyB1c2UgdGhlIGxvYWRfdmFyaWFibGVzIGZ1bmN0aW9uKCkgd2l0aCB0aGUgeWVhciBhbmQgQUNTIDUgeWVhciBwYXJhbWV0ZXINCnZhcnMgPC0gbG9hZF92YXJpYWJsZXMoMjAyMSwgImFjczUiKQ0KIyBsb2FkIHZhcnMgaW50byBhIGRhdGF0YWJsZQ0KZGF0YXRhYmxlKHZhcnMpDQpgYGANCioqRmlndXJlIDUqKiBCeSB1c2luZyB0aGUgc2VhcmNoIGZlYXR1cmUgaW4gdGhlIGRhdGF0YWJsZSwgeW91IHNlZSBleGFtcGxlcyBvZiBhdmFpbGFibGUgcmVzdWx0cy4gRm9yIGV4YW1wbGUgc2VhcmNoICJiYWNoZWxvcidzIiB0byBmaW5kIHZhcmlhYmxlIGNvZGVzIG1vdmluZyBmb3J3YXJkLiANCg0KPGhyIC8+DQoNCiMjIyBJbXBvcnQgRGF0YQ0KDQojIyMjIyBXZSB3aWxsIG5lZWQgdG8gcHVsbCBpbiB0d28gZGF0YXNldHMgYW5kIGV2ZW50dWFsbHkgbWVyZ2UgdGhlIHJlc3VsdHMgaW50byBvbmUgdGFibGUuIA0KIyMjIyMgIkIyNTAxM18wMDYiIGlzIHRoZSBwb3B1bGF0aW9uIG9mIHBlb3BsZSB3aXRoIGJhY2hlbG9yJ3MgZGVncmVlcyB0aGF0IG93biB0aGVpciBob21lLg0KIyMjIyMgIkIyNTAxM18wMTEiIGlzIHRoZSBwb3B1bGF0aW9uIG9mIHBlb3BsZSB3aXRoIGJhY2hlbG9yJ3MgZGVncmVlcyB0aGF0IHJlbnQgdGhlaXIgaG9tZS4NCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyBpbXBvcnQgZGF0YSBhdCB0aGUgdHJhY3QgbGV2ZWwgZm9yIGhvbWUgb3duZXJzDQpiYWNoX293bmVycyA8LSBlcmFzZV93YXRlcihnZXRfYWNzKA0KICBnZW9ncmFwaHkgPSAidHJhY3QiLA0KICB2YXJpYWJsZXMgPSAiQjI1MDEzXzAwNiIsDQogIHN0YXRlID0gIk9SIiwNCiAgY291bnR5ID0gYygiV2FzaGluZ3RvbiIsICJNdWx0bm9tYWgiKSwgIyBzZWxlY3QgbXVsdGlwbGUgY291bnRpZXMNCiAgZ2VvbWV0cnkgPSBUUlVFLCAjIGdldCBtdWx0aXBvbHlnb24gZGF0YSBvZiBPcmVnb24gdHJhY3RzDQogIHByb2dyZXNzX2JhciA9IEZBTFNFDQopKQ0KDQojIGltcG9ydCBkYXRhIGF0IHRoZSB0cmFjdCBsZXZlbCBmb3IgcmVudGVycw0KYmFjaF9yZW50ZXJzIDwtIGdldF9hY3MoDQogIGdlb2dyYXBoeSA9ICJ0cmFjdCIsDQogIHZhcmlhYmxlcyA9ICJCMjUwMTNfMDExIiwNCiAgc3RhdGUgPSAiT1IiLA0KICBjb3VudHkgPSBjKCJXYXNoaW5ndG9uIiwgIk11bHRub21haCIpLCAjIHNlbGVjdCBtdWx0aXBsZSBjb3VudGllcw0KICBnZW9tZXRyeSA9IEZBTFNFLCAjIGdlb21ldHJ5IGlzIGZhbHNlIGJlY2F1c2Ugd2UgYXJlIGdldHRpbmcgb3VyIG11bHRpcG9seWdvbiBkYXRhIGluIHRoZSBvd25lcnMgZGF0YXNldC4gDQogIHByb2dyZXNzX2JhciA9IEZBTFNFDQogICkNCmBgYA0KIyMjIERhdGEgV3JhbmdsaW5nDQoNCiMjIyMjIFVzZSBmdW5jdGlvbnMgb2YgdGhlIHRpZHl2ZXJzZSB0byByZW5hbWUsIHNlbGVjdCwgYW5kIG11dHVhdGUgY29sdW1ucyB0byBmaXQgb3VyIGFuYWx5c2lzLiBTaW5jZSB0aGUgZXN0aW1hdGUgZGF0YSBvcmlnaW5hbGx5IGNvbWVzIGFzIGEgY291bnQsIHdlIHdpbGwgc3VtIHVwIHJlbnRlcnMgYW5kIG93bmVycyB0byBhIGNyZWF0ZSBhIHRvdGFsIGNvbHVtbiBhbmQgYSBwZXJjZW50YWdlIGNvbHVtbiBmb3IgZWFjaC4NCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyBjbGFyaWZ5IHRoZSBuYW1lIG9mIHRoZSBlc3RpbWF0ZSAmIG1vZSBjb2x1bW5zIGJlZm9yZSBqb2luaW5nDQpiYWNoX293bmVycyA8LSBiYWNoX293bmVycyAlPiUNCiAgcmVuYW1lKGVzdGltYXRlX293bmVycyA9IGVzdGltYXRlLCBtb2Vfb3duZXJzID0gbW9lKQ0KDQojIGNsYXJpZnkgdGhlIG5hbWUgb2YgdGhlIGVzdGltYXRlICYgbW9lIGNvbHVtbnMgYmVmb3JlIGpvaW5pbmcNCmJhY2hfcmVudGVycyA8LSBiYWNoX3JlbnRlcnMgJT4lDQogIHJlbmFtZShlc3RpbWF0ZV9yZW50ZXJzID0gZXN0aW1hdGUsIG1vZV9yZW50ZXJzID0gbW9lKSAlPiUNCiAgc2VsZWN0KEdFT0lELCBlc3RpbWF0ZV9yZW50ZXJzLCBtb2VfcmVudGVycykgIyBkcm9wIHVubmVjZXNzYXJ5IHZhbHVlcw0KDQojIGpvaW4gZGF0YWZyYW1lcyBvbiBHRU9JRCwgYW5kIGNyZWF0ZSBwZXJjZW50IGNvbHVtbnMgb2YgZWFjaCBjYXRlZ29yeQ0KYmFjaF9ob3VzaW5nIDwtIGxlZnRfam9pbihiYWNoX293bmVycywgYmFjaF9yZW50ZXJzLCBieT0nR0VPSUQnKSAlPiUNCiAgc2VsZWN0KEdFT0lELCBOQU1FLCBlc3RpbWF0ZV9vd25lcnMsIGVzdGltYXRlX3JlbnRlcnMsIG1vZV9vd25lcnMsIG1vZV9yZW50ZXJzLCBnZW9tZXRyeSkgJT4lDQogIG11dGF0ZShlc3RpbWF0ZV90b3RhbCA9IGVzdGltYXRlX3JlbnRlcnMgKyBlc3RpbWF0ZV9vd25lcnMpICU+JSAjIGNyZWF0ZSBhIHRvdGFsIHZhbHVlDQogIG11dGF0ZShwZXJjZW50X3JlbnRlcnMgPSAoZXN0aW1hdGVfcmVudGVycy9lc3RpbWF0ZV90b3RhbCkqMTAwKSAlPiUgIyBjcmVhdGUgYSAlIG9mIHJlbnRlcnMNCiAgbXV0YXRlKHBlcmNlbnRfb3duZXJzID0gKGVzdGltYXRlX293bmVycy9lc3RpbWF0ZV90b3RhbCkqMTAwKSAlPiUgIyBjcmVhdGUgYSAlIG9mIG93bmVycw0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHJvdW5kKC54LCBkaWdpdHMgPSAyKSkpDQpgYGANCiMjIyBEYXRhIFZpc3VhbGl6YXRpb24gJiBBbmFseXNpcw0KDQojIyMjIyBOb3cgdGhhdCB0aGUgZGF0YSBpcyB3cmFuZ2xlZCB3ZSBjYW4gdmlldyBpdCBpbiBhIHRhYmxlIGJlZm9yZSBtYXBwaW5nIGFuZCBwbG90dGluZyB0aGUgZGVzaXJlZCB2YXJpYWJsZXMuIA0KYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTkuNSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQojIHNlbGVjdCBwZXJjZW50IHJlbnRlcnMgYW5kIG93bmVycw0KYmFjaF9ob3VzaW5nX3RhYmxlIDwtIGJhY2hfaG91c2luZyAlPiUNCiAgc2VsZWN0KE5BTUUsIHBlcmNlbnRfcmVudGVycywgcGVyY2VudF9vd25lcnMpICU+JQ0KICBhcnJhbmdlKC1wZXJjZW50X3JlbnRlcnMpICMgYXJyYW5nZSBpbiBkZXNjZW5kaW5nIG9yZGVyDQoNCiMgcHJldmlldyBpbiBkYXRhdGFibGUNCmRhdGF0YWJsZShiYWNoX2hvdXNpbmdfdGFibGUpDQpgYGANCioqRmlndXJlIDYqKiBBcyBzdXNwZWN0ZWQgaW4gUG9ydGxhbmQgdGhlcmUgYXJlIGEgaGlnaCBudW1iZXIgb2YgcmVudGVycyB3aXRoIGJhY2hlbG9yJ3MgZGVncmVlcy4gTXVsdGlwbGUgdHJhY3RzIHJldmVhbCBhcmVhcyB3aXRoIDEwMCUgb2Ygb3VyIHBhcnRpY3VsYXIgc3R1ZHkgcmVudCB0aGVpciBob21lcy4gDQoNCiMjIyMjIFdlIGFyZSBnb2luZyB0byBzdGFydCB3aXRoIHRoZSBtYXB2aWV3IHBhY2thZ2UgdG8gZ2V0IGEgZ2xpbXBsc2UgaW50byB0aGUgZGF0YS4NCmBgYHtyICxmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD05LjV9DQojIHVzZSB0aGUgcGVyY2VudF9yZW50ZXJzIHZhcmlhYmxlIHRvIGRpc3BsYXkgaW4gdGhlIG1hcHZpZXcNCm1hcHZpZXcoYmFjaF9ob3VzaW5nLA0KICAgICAgICBsYXllci5uYW1lID0gIiUgUmVudGVyczxici8+MjAxNy0yMDIxIEFDUyIsICMgY2hhbmdlIGxheWVyIG5hbWUNCiAgICAgICAgemNvbCA9ICJwZXJjZW50X3JlbnRlcnMiKSAjIHNlbGVjdCBhIHZhcmlhYmxlIHRvIGRpc3BsYXkNCmBgYA0KKipGaWd1cmUgNyoqIE1hcHZpZXcgaXMgcHJvZ3JhbW10aWNhbGx5IGEgc2ltcGxlIHdheSB0byBkaXNwbGF5IGluc2lnaHRmdWwgYW5kIGludGVyYWN0aXZlIGRhdGEuIFdlIGNhbiBub3cgZWFzaXkgdmlzdWFsaXplIHRoYXQgdGhlIGNpdHkgY2VudGVyIGhhcyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgcmVudGVycyB2ZXJzdXMgb3duZXJzIGFuZCBzaGlmdHMgYXMgeW91IG1vdmUgaW50byB0aGUgbW9yZSBydXJhbCBhcmVhcy4NCg0KIyMjIyMgTm93IHRoYXQgd2UgaGF2ZSBzYW1wbGVkIHRoZSBkYXRhIGluIG1hcHZpZXcsIGxldHMgdXNlIGdncGxvdCB0byBjcmVhdGUgYSBzZXQgb2YgY2hsb3JvcGxldGggbWFwcyBmb3IgYm90aCBjYXRlZ29yaWVzIChyZW50aW5nIGFuZCBvd25pbmcpLiANCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD05LjV9DQojIGNyZWF0ZSBnZ3Bsb3QgZm9yIHJlbnRlcnMNCnJlbnRlcnMgPC0gZ2dwbG90KGJhY2hfaG91c2luZywgYWVzKGZpbGwgPSBwZXJjZW50X3JlbnRlcnMpKSArICMgZmlsbCB3aXRoIHBlcmNlbnQgcmVudGVycw0KICBnZW9tX3NmKCkgKyANCiAgdGhlbWVfdm9pZCgpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJyb2NrZXQiKSArICMgdXNlIHJvY2tldCBjb2xvciBzY2hlbWUNCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50IG9mIFBvcHVsYXRpb24gdy8gQmFjaGVsb3IncyBEZWdyZWUgUmVudGluZyBieSBDZW5zdXMgdHJhY3QiLCAjIGNyZWF0ZSBjbGVhciB0aXRsZXMgYW5kIGNhcHRpb25zDQogICAgICAgc3VidGl0bGUgPSAiV2FzaGluZ3RvbiAmIE11bHRub21haCBDb3VudHksIE9yZWdvbiIsDQogICAgICAgZmlsbCA9ICIlIFJlbnRpbmciLA0KICAgICAgIGNhcHRpb24gPSAiMjAxNy0yMDIxIEFDUyB8IHRpZHljZW5zdXMgUiBwYWNrYWdlIikNCg0KIyBjcmVhdGUgZ2dwbG90IGZvciBvd25lcnMNCm93bmVycyA8LSBnZ3Bsb3QoYmFjaF9ob3VzaW5nLCBhZXMoZmlsbCA9IHBlcmNlbnRfb3duZXJzKSkgKyANCiAgZ2VvbV9zZigpICsgDQogIHRoZW1lX3ZvaWQoKSArIA0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAicm9ja2V0IikgKyAgIyB1c2Ugcm9ja2V0IGNvbG9yIHNjaGVtZQ0KICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgb2YgUG9wdWxhdGlvbiB3LyBCYWNoZWxvcidzIERlZ3JlZSBUaGF0IE93biBUaGVpciBIb21lIGJ5IENlbnN1cyB0cmFjdCIsICAjIGNyZWF0ZSBjbGVhciB0aXRsZXMgYW5kIGNhcHRpb25zDQogICAgICAgc3VidGl0bGUgPSAiV2FzaGluZ3RvbiAmIE11bHRub21haCBDb3VudHksIE9yZWdvbiIsDQogICAgICAgZmlsbCA9ICIlIE93bmVycyIsDQogICAgICAgY2FwdGlvbiA9ICIyMDE3LTIwMjEgQUNTIHwgdGlkeWNlbnN1cyBSIHBhY2thZ2UiKQ0KDQojIHVzZSBwbG90X2dyaWQgZnJvbSB0aGUgY293cGxvdCBsaWJyYXJ5IHRvIHN0YWNrIHRoZSBtYXBzDQpwbG90X2dyaWQocmVudGVycywgb3duZXJzLCBuY29sPTEsIGFsaWduID0gImh2IikNCmBgYA0KKipGaWd1cmUgOCoq